﻿using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using EPiMVC.Reflection;
using EPiServer;
using EPiServer.Core;

namespace EPiMVC.Routing
{
    public class EPiServerRoute : RouteBase
    {
        public const string PageReferenceKey = "pageReference";
        public const string CurrentPageReferenceKey = "currentPageReference";

        private RouteConfiguration configuration;

        public EPiServerRoute()
            : this(new RouteConfiguration(), new MvcRouteHandler()) {}

        public EPiServerRoute(RouteConfiguration configuration)
            : this(configuration, new MvcRouteHandler()) {}

        public EPiServerRoute(RouteConfiguration configuration, IRouteHandler routeHandler)
        {
            this.configuration = configuration;
            RouteHandler = routeHandler;
        }

        public IRouteHandler RouteHandler { get; set; }

        private IPageSource dataFactory;

        public IPageSource DataFactory
        {
            get
            {
                if (dataFactory == null)
                    dataFactory = EPiServer.DataFactory.Instance;

                return dataFactory;
            }

            set
            {
                dataFactory = value;
            }
        }

        public override RouteData GetRouteData(System.Web.HttpContextBase httpContext)
        {
            RouteData routeData = new RouteData(this, RouteHandler);
            RequestContext requestContext = new RequestContext(httpContext, routeData);
            new PageRouteMapper(requestContext, configuration).SetRouteValues();
            
            if (routeData.Values[CurrentPageReferenceKey] == null)
                return null;
            
            return routeData;
        }


        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            if (!PageReferenceIsSpecified(values))
                return null;

            if (values.ContainsKey("controller"))
                return null;

            PageReference pageLink = (PageReference) values[PageReferenceKey];
            
            string virtualPath = configuration.PageResolver.GetFriendlyUrl(pageLink);
            if(virtualPath.StartsWith("/"))
                virtualPath = virtualPath.Remove(0, 1);
            
            List<string> routeValueKeysToAdd = values.Keys.Where(key => key != PageReferenceKey).ToList();
            
            PageData linkedPage = DataFactory.GetPage(pageLink);
            if(linkedPage.TypeHasAttribute<RouteEndingAttribute>())
            {
                IEnumerable<string> routeParameters = PathParser.GetUrlSegments(linkedPage.GetTypeAttribute<RouteEndingAttribute>().RouteUrlEnding);
                foreach (string routeParameter in routeParameters)
                {
                    if (!values.ContainsKey(routeParameter))
                        break;

                    virtualPath += values[routeParameter] + "/";
                    routeValueKeysToAdd.Remove(routeParameter);
                }
            }
            foreach (string key in routeValueKeysToAdd)
                virtualPath = UriSupport.AddQueryString(virtualPath, key, values[key].ToString());
            
            return new VirtualPathData(this, virtualPath);
        }

        private static bool PageReferenceIsSpecified(RouteValueDictionary values)
        {
            if (values[PageReferenceKey] == null)
                return false;

            if (!(values[PageReferenceKey] is PageReference))
                return false;

            return true;
        }
    }
}
